iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 17
0
Mobile Development

Android Kotlin開發 -小嫩雞的30篇精選筆記系列 第 17

Kotlin : 單例模式及kotlin object運作原理

  • 分享至 

  • xImage
  •  

簡介

  • 單例模式是一種軟體設計模式,規則是每個類別只能有一個實例存在,並且能提供全域訪問。當多個類別呼叫它時,拿到的都會是同一個實例。該singleton類別可以自己產生一個自己的實例,也可以透過工廠類別來產生。

  • 在一個典型的APP中,我們常只需要物件的一個全域實例,無論是直接使用它還是簡單地將它傳遞給另一個類。包括OkHttpClient, HttpLoggingInterceptor, retrofit,Gson,SharedPreferences和倉庫類等。 如果我們把這些類產生實體了多個物件,我們就會遇到許多問題,比如異常的APP反應,資源過度使用和其他混亂的結果。

在java中實現單例模式

public class Singleton{
    
    private static Singleton instance = null;
    private Singleton(){
        //構造函數    
    }
 
    private synchronized static void createInstance(){
          if(instance == null){
               instance = new Singleton();
          }
    }

    public static Singleton getInstance(){
          if(instance == null) createInstance();
          return instance;
    }
 
 
}
  • 裡面使用到synchronized關鍵字,原因是要保護執行緒安全,表示這個function裡面一次只有一個執行緒能夠進入,其他執行緒要在外面乖乖排隊。這樣就不會有多個執行緒因為同時執行到此function而產生多個實例的問題。
  • 缺點是會有執行緒堵塞的問題,降低整體性能。

在kotlin中實現單例模式

 class MainActivity : AppCompatActivity() {

    object test{

    }

    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

    }


}

一行程式碼,結束。

  • 此用法稱為「Object Declaration」。
  • object關鍵字代表其包含了上面單例的特性。我們試著把它decompile就會變成下面這樣。
public static final class test {
      public static final MainActivity.test INSTANCE;

      private test() {
      }

      static {
         MainActivity.test var0 = new MainActivity.test();
         INSTANCE = var0;
      }
   }

  • 會發現跟上面的java寫法非常相似。
  • 會發現它在static作用域裡幫你實例化了test類別。而jvm虛擬機在載入類別時,就會執行static作用域,也就是說kotlin中的object{}都會在一開始就被實例化
  • 要注意的是,object沒有用synchronized來保障執行緒安全,這部分必須自己處理。

那如果我們想在static區塊加入更多東西,好讓他們在app一開啟就被執行呢?
寫在init{}初始化區塊裡就可以啦~

object test{
        init{
            println("init")
        }
        fun wangwang(){
            println("wangwang")
        }
    }

decompile之後

 public static final class test {
      public static final MainActivity.test INSTANCE;

      public final void wangwang() {
         String var1 = "wangwang";
         System.out.println(var1);
      }

      //構造函數一定是空的
      private test() {
      }

      static {
         MainActivity.test var0 = new MainActivity.test();
         INSTANCE = var0;
         
         String var1 = "init";
         System.out.println(var1);
      }
   }
}
  • 發現static區塊確實多了我們新增的兩行程式碼。

那類別加載的時候就初始化構造單例,是不是對空間的利用不太好?
這一點問題不大,虛擬機在運行程序的時候,並不是在啟動時就將所有的類別都初始化完成,而是在真正使用它的時候才會初始化。

參考資料:

1. 講解kotlin單例、帶參單例及封裝


上一篇
Kotlin : kotlin中的object用法
下一篇
Kotlin : java的靜態成員與特性在Kotlin中該如何使用
系列文
Android Kotlin開發 -小嫩雞的30篇精選筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言